import json
from django.utils import timezone

from django.db import transaction
from django.db.models import Max
from rest_framework.response import Response
from rest_framework import status
from rest_framework.decorators import action
from rest_framework import serializers, filters
from rest_framework.viewsets import ModelViewSet, GenericViewSet
from rest_framework.mixins import CreateModelMixin, ListModelMixin
from rest_framework.permissions import IsAuthenticated
from django_filters.rest_framework import DjangoFilterBackend

from .models import Table, TableFields, DataRecord
from .serializers import (TableWriteSerializer, TableRetrieveSerializer, DataRecordDestroySerializer,
                          TableFieldsCreateSerializer, TableFieldsReadSerializer, TableFieldsUpdateSerializer,
                          DataRecordCreateSerializer, DataRecordReadSerializer, DataRecordUpdateSerializer,
                          TableListSerializer)
from .filters import DataRecordFilter, TableFieldsFilter
from apps.base.pagination import PageNumberPagination


class TableViewSet(ModelViewSet):
    """
        list:
            查看自定义表名称列表页信息
        create:
            创建自定义表名称
        update:
            更新自定义表名称
        partial_update:
            局部更新自定义表名称
        retrieve:
            获取自定义表名称详情
        destroy:
            删除自定义表名称
    """
    pagination_class = PageNumberPagination
    queryset = Table.objects.all()
    filter_backends = (DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter)
    search_fields = ('name', 'descriptions')
    ordering_fields = ('created_at', 'name')

    def get_serializer_class(self):
        if self.action in ['create', 'update', 'partial_update']:
            return TableWriteSerializer
        if self.action == 'retrieve':
            return TableRetrieveSerializer
        return TableListSerializer

    def get_permissions(self):
        if self.action in ['list', 'retrieve']:
            return [IsAuthenticated()]
        return [IsAuthenticated()]


class TableFieldsViewSet(ModelViewSet):
    """
        list:
            查看各表字段信息
        create:
            为表新增字段
        retrieve:
            获取表字段类型详情
    """
    pagination_class = PageNumberPagination
    queryset = TableFields.objects.all()
    filter_backends = (DjangoFilterBackend, filters.OrderingFilter)
    filter_class = TableFieldsFilter
    ordering_fields = ('order', )

    def get_serializer_class(self):
        if self.action == 'create':
            return TableFieldsCreateSerializer
        if self.action in ['update', 'partial_update']:
            return TableFieldsUpdateSerializer
        return TableFieldsReadSerializer

    def get_permissions(self):
        if self.action in ['list', 'retrieve']:
            return [IsAuthenticated()]
        return [IsAuthenticated()]

    @transaction.atomic
    def destroy(self, request, *args, **kwargs):
        """数据表级联删除"""
        instance = self.get_object()
        DataRecord.objects.filter(table=instance.table, field_tag=instance.field_tag).delete()
        self.perform_destroy(instance)
        return Response(status=status.HTTP_204_NO_CONTENT)


class DataRecordViewSet(CreateModelMixin, ListModelMixin, GenericViewSet):
    """
        create:
            新增数据记录（需要指定table的id)
        data:
            获取数据集
        update_instance:
            修改数据
        del_instance:
            删除数据
    """
    pagination_class = PageNumberPagination
    queryset = DataRecord.objects.all()
    filter_backends = (DjangoFilterBackend, filters.OrderingFilter)
    ordering_fields = ('row_num',)
    filter_class = DataRecordFilter

    def get_serializer_class(self):
        if self.action == 'create':
            return DataRecordCreateSerializer
        if self.action == 'update_instance':
            return DataRecordUpdateSerializer
        if self.action == 'del_instance':
            return DataRecordDestroySerializer
        return DataRecordReadSerializer

    def get_serializer(self, *args, **kwargs):
        kwargs['context'] = self.get_serializer_context()
        if self.action in ['create', 'update_instance']:
            if self.request and self.request.query_params and self.request.query_params.get('table', None):
                table_id = self.request.query_params.get('table')
                _queryset = Table.objects.filter(id=table_id)
                if _queryset.count() != 1:
                    raise serializers.ValidationError('id参数错误，请核对')
                fields = self.get_all_fields_by_table(_queryset.first())
                kwargs.update(fields=fields)
                return self.get_serializer_class()(*args, **kwargs)
            raise serializers.ValidationError('请指定table，用于生成动态的create序列化器，写法 /url/?table=id')

        else:
            serializer_class = self.get_serializer_class()
            return serializer_class(*args, **kwargs)

    def get_permissions(self):
        if self.action in ['list', 'retrieve']:
            return [IsAuthenticated()]
        return [IsAuthenticated()]

    def get_all_fields_by_table(self, instance):
        fields = instance.table_fields_table.all()
        res_dict = {}
        for field in fields:
            _each = {'label': field.field_name, 'help_text': field.descriptions, 'write_only': True}
            _each['required'] = field.is_blank if self.action == 'create' else False
            extra_conditions = json.loads(field.extra_conditions) if field.extra_conditions else None
            if extra_conditions:
                default = json.loads(field.extra_conditions).get('default_value', None)
                # default 与 required不能同时存在，这里将default优先级调高。
                if default:
                    _each = {'label': field.field_name, 'help_text': field.descriptions, 'default': default,
                             'write_only': True}
                for i in ['min_value', 'max_value', 'min_length', 'max_length']:
                    res = json.loads(field.extra_conditions).get(i, None)
                    if res is not None:
                        _each[i] = res
            res_dict[(field.field_tag, field.field_type)] = _each
        return res_dict

    @transaction.atomic
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        table_id = self.request.query_params.get('table')
        table = Table.objects.filter(id=table_id).first()
        max_row = DataRecord.objects.filter(table=table_id).aggregate(max=Max('row_num'))[
            'max'] if DataRecord.objects.filter(table=table_id) else 0
        records = [DataRecord(table=table, field_tag=item[0], field_value=item[1], created_by=request.user,
                              row_num=max_row + 1) for item in serializer.validated_data.items()]
        DataRecord.objects.bulk_create(records)
        return Response(serializer.validated_data, status=status.HTTP_201_CREATED)

    @action(['get', ], detail=False)
    def data(self, request):
        """这里重写列表页与详情页 自定义分页并自定义搜索"""
        table_id = request.query_params.get('table')
        table_queryset = Table.objects.filter(id=table_id)
        if table_queryset.count() != 1:
            raise serializers.ValidationError('id参数错误，请核对')
        table = table_queryset.first()
        # 查看详情
        row_num = request.query_params.get('row_num')
        if row_num and row_num.isdigit():
            res = DataRecord.get_instance_dict(int(row_num), table)
            return Response(res if res else None)
        # 搜索
        queryset = DataRecord.objects.filter(table=table_id)
        search = request.query_params.get('search')
        if search:
            search_fields = table.table_fields_table.filter(is_search=True).values_list('field_tag', flat=True)
            if search_fields:
                queryset = queryset.filter(field_tag__in=search_fields, field_value__icontains=search)
        all_rows = list(set(queryset.values_list('row_num', flat=True)))
        count = len(all_rows)
        if count == 0:
            return Response({'count': count, 'results': []})
        # 排序
        ordering = request.query_params.get('ordering')
        ordering_res = True if ordering and ordering == '-row_num' else False
        all_rows.sort(reverse=ordering_res)
        # 分页
        _page = request.query_params.get(PageNumberPagination.page_query_param)
        page = int(_page) if _page and _page.isdigit() else 1
        _page_size = request.query_params.get(PageNumberPagination.page_size_query_param)
        page_size = int(_page_size) if _page_size and _page_size.isdigit() else PageNumberPagination.page_size
        row_range = all_rows[(page - 1) * page_size: page * page_size]
        return Response({'count': count, 'results': DataRecord.get_data_by_rows(row_range, table)})

    @action(['get', 'post'], detail=False)
    @transaction.atomic
    def update_instance(self, request, *args, **kwargs):
        if request.method == 'GET':
            return Response()
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        table_id = request.query_params.get('table')
        table = Table.objects.filter(id=table_id).first()
        row_num = serializer.validated_data.pop('row_num', 0)
        old_records = DataRecord.get_instance_dict(int(row_num), table)
        del old_records['row_num']
        old_records.update(serializer.validated_data)
        # 取出历史数据的创建人和创建时间
        _record = DataRecord.objects.filter(table=table_id, row_num=row_num).first()
        DataRecord.objects.filter(table=table_id, row_num=row_num).delete()
        records = [DataRecord(table=table, field_tag=item[0], field_value=item[1],
                              modified_by=request.user if _record else None,
                              created_by=_record.created_by if _record else request.user,
                              created_at=_record.created_at if _record else timezone.now(),
                              row_num=row_num) for item in old_records.items()]
        DataRecord.objects.bulk_create(records)
        return Response(serializer.validated_data)

    @action(['get', 'post'], detail=False)
    @transaction.atomic
    def del_instance(self, request, *args, **kwargs):
        if self.request and self.request.query_params and self.request.query_params.get('table', None):
            table_id = self.request.query_params.get('table')
            _queryset = Table.objects.filter(id=table_id)
            if _queryset.count() != 1:
                raise serializers.ValidationError('id参数错误，请核对')
        if request.method == 'GET':
            return Response()
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        table_id = request.query_params.get('table')
        old_record = DataRecord.objects.filter(table=table_id, row_num=serializer.validated_data['row_num'])
        if old_record:
            old_record.delete()
            return Response(status=status.HTTP_204_NO_CONTENT)
        raise serializers.ValidationError('数据行数不存在')

